﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using haptic.src.engine.debug;

namespace haptic.src.engine.collisions
{
    [Serializable]
    public class BorderCollider : ICollider
    {
        #region Constructor
        /// <summary>
        /// only for serialization
        /// </summary>
        public BorderCollider()
        {

        }
        public BorderCollider(Vector2 vNormal, float fC)
        {
            Set(vNormal, fC);
        }
        public BorderCollider(Vector2 vNormal, Vector2 vPos)
        {
            Set(vNormal, vPos);
        }
        public BorderCollider(BorderCollider oPlane)
        {
            Set(oPlane.m_vNormal, oPlane.m_fC);
        }
        public ICollider Clone()
        {
            return new BorderCollider(this);
        }

        #endregion
        #region Edit
        public void Set(Vector2 vNormal, float fC)
        {
            m_vNormal = vNormal;
            m_fC = fC;
        }
        public void Set(Vector2 vNormal, Vector2 vPos)
        {
            m_vNormal = vNormal;
            m_fC = -(Vector2.Dot(vNormal, vPos));
        }
        public void SetCenter(Vector2 vCenter)
        {
            m_fC = -(Vector2.Dot(vNormal, vCenter));
        }
        #endregion
        #region Collisions
        public bool IsInside(Vector2 vPos)
        {
            return Vector2.Dot(m_vNormal, vPos) + m_fC <= 0.0f;
        }
        public bool IsInside(ICollider oCollider)
        {
            return false;
        }

        public bool IsColliding(AABBCollider oAABBCol, CollisionHit oCollisionHit)
        {
            Vector2 vTmp = new Vector2(oAABBCol.vExtents.X, -oAABBCol.vExtents.Y);
            Vector2[] vP = new Vector2[4];
            vP[0] = oAABBCol.vCenter - oAABBCol.vExtents;
            vP[1] = oAABBCol.vCenter + vTmp;
            vP[2] = oAABBCol.vCenter + oAABBCol.vExtents;
            vP[3] = oAABBCol.vCenter - vTmp;

            float[] fD = new float[4];

            fD[0] = Vector2.Dot(m_vNormal, vP[0]);
            fD[1] = Vector2.Dot(m_vNormal, vP[1]);
            fD[2] = Vector2.Dot(m_vNormal, vP[2]);
            fD[3] = Vector2.Dot(m_vNormal, vP[3]);

            if (fD[0] > m_fC && fD[1] > m_fC && fD[2] > m_fC && fD[3] > m_fC)
                return false;

            if (oCollisionHit != null)
            {
                oCollisionHit.m_vNormal = m_vNormal;

                int iMin = 0;
                for (int i = 1; i < 4; i++)
                {
                    if (fD[i] < fD[iMin])
                        iMin = i;
                }
                Vector2 vPMin = vP[iMin];
                float fDMin = fD[iMin];

                oCollisionHit.m_vTargetContact = vPMin - (fDMin - fC) * m_vNormal;
                oCollisionHit.m_vSourceContact = vPMin;
            }

            return true;
        }

        public bool IsColliding(ICollider oCollider, CollisionHit oCollisionHit)
        {
            if (oCollider == null)
                return false;

            if (oCollider.GetType() == typeof(AABBCollider))
            {
                AABBCollider oAABBCol = (AABBCollider)oCollider;
                return IsColliding(oAABBCol, oCollisionHit);
            }
            return false;
        }

        public bool IsColliding(ICollider oCollider)
        {
            return IsColliding(oCollider, null);
        }

        #endregion

        public BoundingBox GetBoundingBox()
        {
            return null;
        }

        #region Draw
        public void DrawDebug(DebugRenderer oDebug)
        {
        }
        #endregion

        #region Attributes
        private Vector2 m_vNormal;
        public Vector2 vNormal { get { return m_vNormal; } }
        private float m_fC;
        public float fC { get { return m_fC; } }
        #endregion
    }
}
